package test.my.com.myapplicationtest.paint_view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;

import java.util.LinkedList;

import static android.content.Context.WINDOW_SERVICE;

/**
 * Created by ah on 2016/3/11.
 * 处理图片涂抹并保存功能
 */
public class PaintView extends View {

    public static final float PAINT_STROKE_WIDTH_COEFFICIENT = 100; // 画笔粗细系数
    public static final float DEFAULT_PAINT_STROKE_WIDTH = 10f; // 默认画笔粗细

    private Paint mPaint;
    private Paint mBitmapPaint;
    private Canvas mCanvas;
    private Path mPath;
    private Bitmap mBitmap;

    private Context mContext;

    private float mX;
    private float mY;

    private WindowManager wm;
    private int windowWidth;
    private int windowHeight;

    // 保存当前图片所画path
    private LinkedList<DrawPath> mSaveList;
    // 保存已经撤销的path
    private LinkedList<DrawPath> mDeleteList;
    private DrawPath mDrawPath;

    // 使所绘制的图片居中 x y
    private int mBitmapPositionX;
    private int mBitmapPositionY;

    // PaintView 所需属性
    private PaintAttributeModel mPaintAttributeModel;


    public PaintView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

    public PaintView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
    }

    private void init() {
        wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
        windowWidth = wm.getDefaultDisplay().getWidth();
        windowHeight = wm.getDefaultDisplay().getHeight();

        defaultViewWidthHeight();

        mSaveList = new LinkedList<>();
        mDeleteList = new LinkedList<>();

        initCanvas();
    }

    /**
     * 如果没有设置绘画view的宽高，默认view宽高为屏幕宽高
     */
    private void defaultViewWidthHeight(){
        if(mPaintAttributeModel.getViewWidth() == 0){
            mPaintAttributeModel.setViewWidth(windowWidth);
            mPaintAttributeModel.setViewHeight(windowHeight);
        }
    }

    /**
     * 绘画前属性准备
     * @param paintAttributeModel
     */
    public void preparePaint(PaintAttributeModel paintAttributeModel){
        this.mPaintAttributeModel = paintAttributeModel;
        init();
        invalidate();
    }

    /**
     * 初始化图片
     */
    private void initCanvas() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);// 抗锯齿
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);// 始末端圆角
        mPaint.setDither(true); // 防抖动
        mPaint.setStrokeWidth(caculateStrokeWidth());
        mBitmap = BitmapUtil.createBitmapByPath(mPaintAttributeModel.getResPath(), mPaintAttributeModel.getViewWidth(), mPaintAttributeModel.getViewHeight());
        mCanvas = new Canvas(mBitmap);
        mPath = new Path();

        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        calateBitmapPosition();
        // 所绘制目标图片的mCanvas移动到显示图片canvas的位置。
        mCanvas.translate(0, -mBitmapPositionY);
    }

    /**
     * 计算图片显示位置（显示居中）
     */
    private void calateBitmapPosition() {
        float scale_v = (float)mPaintAttributeModel.getViewWidth()/mPaintAttributeModel.getViewHeight();
        float scale_b = (float)mBitmap.getWidth()/mBitmap.getHeight();
        if (scale_b > scale_v) {
            mBitmapPositionX = 0;
            mBitmapPositionY = mPaintAttributeModel.getViewHeight() / 2 - mBitmap.getHeight() / 2;
        } else if(scale_b < scale_v){
            mBitmapPositionY = 0;
            mBitmapPositionX = mPaintAttributeModel.getViewWidth() / 2 - mBitmap.getWidth() / 2;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.BLACK);
        if(mBitmap != null){
            canvas.drawBitmap(mBitmap, mBitmapPositionX, mBitmapPositionY, mBitmapPaint);
        }
        if (mPath != null) {
            // 实时的显示
            mCanvas.drawPath(mPath, mPaint);
        }
    }

    /**
     * 一步一步撤销path
     */
    public void cancelPath() {
        if (mSaveList.size() > 0) {
            initCanvas();
            DrawPath dp = mSaveList.peekLast();
            mDeleteList.add(dp);
            mSaveList.removeLast();
            for (DrawPath drawPath : mSaveList) {
                mCanvas.drawPath(drawPath.path, drawPath.paint);
            }
            invalidate();
        }
    }

    /**
     * 一步一步恢复path
     */
    public void recoverPath() {
        if (mDeleteList.size() > 0) {
            initCanvas();
            DrawPath dp = mDeleteList.getLast();
            mSaveList.add(dp);
            mDeleteList.removeLast();
            for (DrawPath drawPath : mSaveList) {
                mCanvas.drawPath(drawPath.path, drawPath.paint);
            }
            invalidate();
        }
    }

    /**
     * 清除所有path
     */
    public void clearPath() {
        initCanvas();
        invalidate();
        mSaveList.clear();
        mDeleteList.clear();
    }

    /**
     * 是否已经对图片进行操作
     * @return
     */
    public boolean isPicturePainted(){
        return mSaveList.size()>0;
    }

    /**
     * 保存操作后的图片
     */
    public void saveDoneImage(SavePaintPictureCallBack savePaintPictureCallBack) {
        mCanvas.save(Canvas.ALL_SAVE_FLAG);
        mCanvas.restore();
        // 如果用户没有设置desPath时，则默认为覆盖原图。
        String desPath = TextUtils.isEmpty(mPaintAttributeModel.getDesPath())?mPaintAttributeModel.getResPath():mPaintAttributeModel.getDesPath();
        if(BitmapUtil.createImage(mBitmap, desPath)){
            savePaintPictureCallBack.savePaintPictureSuccess(desPath);
        }
    }

    @Override
    public void setVisibility(int visibility) {
        super.setVisibility(visibility);
        if(mBitmap != null && visibility == GONE){
            mBitmap.recycle();
            mBitmap = null;
        }
    }

    /**
     * 结束paint管理
     */
    private void finishPaint(){

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float currentX = event.getX();
        float currentY = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                float downX = event.getX();
                float downY = event.getY();

                mX = downX;
                mY = downY;

                mPath = new Path();
                mDrawPath = new DrawPath();
                mDrawPath.path = mPath;
                mDrawPath.paint = mPaint;

                mPath.reset();
                mPath.moveTo(downX, downY);
                break;
            case MotionEvent.ACTION_MOVE:
                float dx = Math.abs(currentX - mX);
                float dy = Math.abs(currentY - mY);

                //两点之间的距离大于等于3时，生成贝塞尔绘制曲线
                if (dx > 3 || dy > 3) {
                    //设置贝塞尔曲线的操作点为起点和终点的一半
                    float hx = (mX + currentX) / 2;
                    float hy = (mY + currentY) / 2;
                    //二次贝塞尔，实现平滑曲线；mX, mY为操作点，hx, hy为终点
                    mPath.quadTo(mX, mY, hx, hy);
                }
                //第二次执行时，第一次结束调用的坐标值将作为第二次调用的初始坐标值
                mX = currentX;
                mY = currentY;
                break;
            case MotionEvent.ACTION_UP:
                mPath.lineTo(mX, mY);
                mSaveList.add(mDrawPath);
                mPath = null;
                break;
        }
        invalidate();
        return true;
    }


    /**
     * 计算画笔粗细
     *
     * @return
     */
    private int caculateStrokeWidth() {
        int strokeWidth;
        if (mPaintAttributeModel.getStrokeWidthCoefficient() == 0) {
            mPaintAttributeModel.setStrokeWidthCoefficient(PAINT_STROKE_WIDTH_COEFFICIENT);
        }
        strokeWidth = (int) ((windowHeight / windowWidth) * mPaintAttributeModel.getStrokeWidthCoefficient() / DEFAULT_PAINT_STROKE_WIDTH * mContext.getResources().getDisplayMetrics().density);
        return strokeWidth;
    }

    /**
     * path类
     */
    class DrawPath {
        Path path;
        Paint paint;
    }

    /**
     * 成功保存操作后的图片接口
     */
    public interface SavePaintPictureCallBack{
        void savePaintPictureSuccess(String desPath);
    }
}
